﻿using log4net;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;

namespace APIDemo.Filters
{
    public class LogAttribute : ActionFilterAttribute
    {
        private ILog log = LogManager.GetLogger(Startup.repository.Name, typeof(LogAttribute));     

        private string LogFlag { get; set; }
        private string ActionArguments { get; set; }

        /// <summary>
        /// 请求体中的所有值
        /// </summary>
        private string RequestBody { get; set; }

        private Stopwatch Stopwatch { get; set; }

        public LogAttribute(string logFlag)
        {
            LogFlag = logFlag;
        }
        /// <summary>
        /// 请求到达该控制器的动作方法之前，OnActionExecuting 方法会被调用
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);

            // 添加获取请求的请求体
            long contentLen = context.HttpContext.Request.ContentLength == null ? 0 : context.HttpContext.Request.ContentLength.Value;
            if (contentLen > 0)
            {
                // 读取请求体中所有内容
                System.IO.Stream stream = context.HttpContext.Request.Body;
                if (context.HttpContext.Request.Method == "POST")
                {
                    stream.Position = 0;
                }
                byte[] buffer = new byte[contentLen];
                stream.Read(buffer, 0, buffer.Length);
                // 转化为字符串
                RequestBody = System.Text.Encoding.UTF8.GetString(buffer);
            }

            ActionArguments = Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments);

            Stopwatch = new Stopwatch();
            Stopwatch.Start();
        }
        /// <summary>
        /// 当控制器的动作方法执行完成后，OnActionExecuted 方法会被调用，常见用法比如处理动作方法的返回结果、记录响应日志
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
            // 停止计时器操作
            Stopwatch.Stop();

            string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
            string method = context.HttpContext.Request.Method;

            string qs = ActionArguments;

            dynamic result = context.Result.GetType().Name == "EmptyResult" ? new { Value = "无返回结果" } : context.Result as dynamic;
         
            string res = "在返回结果前发生了异常";
            try
            {
                if (result != null)
                {
                    res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
                }
            }
            catch (System.Exception)
            {
                res = "日志未获取到结果或者返回的数据无法序列化";
            }

            // 获取客户端访问ip
            string ip = context.HttpContext.Connection.RemoteIpAddress.ToString(); 
            log.Info($"\n 方法：{LogFlag} \n " +
                $"访问ip：{ip} \n " +
                $"地址：{url} \n " +
                $"方式：{method} \n " +
                $"请求体：{RequestBody} \n " +
                $"参数：{qs}\n " +
                $"结果：{res}\n " +
                $"耗时：{Stopwatch.Elapsed.TotalMilliseconds} 毫秒（控制器内对应方法执行完毕的时间）");

        }
    }
}
